﻿/*******************************************************************************
 * AAEngine
 * Copyright (c) 2010 Mike Jarosch
 *
 * Original source PushButton Engine:
 * Copyright (C) 2009 PushButton Labs, LLC
 * For more information see http://www.pushbuttonengine.com
 *
 * This file is licensed under the terms of the MIT license, which is included
 * in the "MIT License.txt" file at the root directory of this SDK.
 ******************************************************************************/

using System;
using System.Collections.Generic;
using AAEngine.Engine.Debug;
using AAEngine.Engine.Entities;

namespace AAEngine.Engine.Core
{
    /// <summary>
    /// The name manager stores references to PBObjects that have been given     
    /// names. These AAObjects can be looked up by name.
    /// </summary>
    public sealed class NameManager
    {
        Dictionary<string, IAAObject> _objects = new Dictionary<string, IAAObject>();

        public IDictionary<string, IAAObject> ObjectList
        {
            get
            {
                return _objects;
            }
        }

        /// <summary>
        /// Registers a AAObject with it's name and alias.
        /// </summary>
        /// <param name="PBObject">The AAObject to add.</param>
        public void Add(IAAObject item)
        {
            bool isNameValid = !String.IsNullOrEmpty(item.Name);
            bool isAliasValid = !String.IsNullOrEmpty(item.Alias);

            if (isNameValid && _objects.ContainsKey(item.Name))
            {
                Logger.Warn(this, "Add", "An AAObject with the name " + item.Name + " already exists. Future lookups by this name will return this new entity. Did you mean to make this entity a template?");
            }

            //if (TemplateManager.VERBOSE_LOGGING)
            //{
            //    Logger.Print(this, "Registering PBObject '" + PBObject.Name + "'");
            //}

            if (isNameValid)
            {
                _objects[item.Name] = item;
            }

            if (isAliasValid)
            {
                _objects[item.Alias] = item;
            }
        }

        /// <summary>
        /// Removes an object from the manager.
        /// </summary>
        /// <param name="PBObject">The PBObject to remove.</param>
        public void Remove(IAAObject item)
        {
            // Unregister its alias, if it has one and the alias points to us.
            if (!String.IsNullOrEmpty(item.Alias) && _objects[item.Name] == _objects[item.Alias])
            {
                _objects.Remove(item.Alias);
            }

            // And the normal name, if it is us.
            if (!String.IsNullOrEmpty(item.Name) && _objects[item.Name] == item)
            {
                _objects.Remove(item.Name);
            }
        }

        /// <summary>
        /// Looks up a IAAObject with the specified name.
        /// </summary>
        /// <param name="name">The name of the object to look up.</param>
        /// <returns>The object with the specified name, or null if it wasn't found.</returns>
        public IAAObject Lookup(string name)
        {
            if (_objects.ContainsKey(name))
            {
                return _objects[name];
            }

            return null;
        }

        public string ValidateName(string name)
        {
            if (!_objects.ContainsKey(name))
            {
                return name;
            }

            var index = 1;
            var testName = String.Format("{0}{1}", name, index);
            while (_objects.ContainsKey(testName))
            {
                testName = String.Format("{0}{1}", name, index++);
            }

            return testName;
        }

        /// <summary>
        /// Looks up a component on an entity that has been registered. The same         
        /// conditions apply as with the LookupComponentByType method on IEntity.
        /// </summary>
        /// <param name="name">The name of the entity on which the component exists.</param>
        /// <param name="componentType">The type of the component to lookup.</param>
        /// <returns>The component of the specified type on the object with the specified name, or null if it wasn't found.</returns>
        public IEntityComponent LookupComponentByType(string name, Type componentType)
        {
            IEntity entity = Lookup(name) as IEntity;
            if (entity == null)
            {
                return null;
            }

            return entity.LookupComponentByType(componentType);
        }

        /// <summary>
        /// Looks up components on an entity that has been registered. The same
        /// conditions apply as with the lookupComponentsByType method on IEntity.
        /// </summary>
        /// <param name="name">The name of the entity on which the component exists.</param>
        /// <param name="componentType">The type of the components to lookup.</param>
        /// <returns></returns>
        public IEnumerable<IEntityComponent> LookkupComponentsByType(string name, Type componentType)
        {
            IEntity entity = Lookup(name) as IEntity;
            if (entity == null)
            {
                return null;
            }

            return entity.LookupComponentsByType(componentType);
        }

        /// <summary>
        /// Looks up a component on an entity that has been registered. The same         
        /// conditions apply as with the FindComponent&lt;T&gt; method on IEntity.
        /// </summary>
        /// <param name="name">The name of the entity on which the component exists.</param>
        /// <param name="componentName">The name of the component.</param>
        /// <returns>The component with the specified name on the object with the specified name, or null if it wasn't found.</returns>
        public IEntityComponent LookupComponentByName(string name, string componentName)
        {
            IEntity entity = Lookup(name) as IEntity;
            if (entity == null)
            {
                return null;
            }

            return entity.LookupComponentByName(componentName);
        }
    }
}
